package com.flame.system.tools.controller;

import com.flame.auth.core.annotation.HasAuth;
import com.flame.core.protocol.PageResult;
import com.flame.core.protocol.Result;
import com.flame.core.utils.HttpUtils;
import com.flame.core.utils.StringUtils;
import com.flame.core.utils.ZipUtils;
import com.flame.system.tools.controller.vo.CodeGenerateVo;
import com.flame.system.tools.controller.vo.DbDatasourceTableVo;
import com.flame.system.tools.controller.vo.DbDatasourceVo;
import com.flame.system.tools.controller.vo.FormDataVo;
import com.flame.system.tools.entity.DbColumn;
import com.flame.system.tools.entity.DbDatasource;
import com.flame.system.tools.entity.GeneratedCode;
import com.flame.system.tools.service.GeneratorService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;

@RestController
public class GeneratorController {

    @Autowired
    private GeneratorService generatorService;

    @PostMapping("/form/code/download")
    public void formCodeDownload(@RequestBody FormDataVo formDataVo, HttpServletResponse response) {
        String formCode = generatorService.generateFormCode(formDataVo);
        String dirLocation = System.getProperty("java.io.tmpdir") + File.separator + "flame" + File.separator + "code";
        String fileLocation =
            System.getProperty("java.io.tmpdir") + File.separator + "flame" + File.separator + "code" +
                File.separator + "formData.vue";
        try {
            File directory = new File(dirLocation);
            if (!directory.exists()) {
                directory.mkdirs();
            }
            File file = new File(fileLocation);
            if (file.exists()) {
                file.delete();
            }

            FileOutputStream outputStream = new FileOutputStream(file);
            outputStream.write(formCode.getBytes(StandardCharsets.UTF_8));
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        HttpUtils.writeFile(response, null, fileLocation, true);
    }

    @PostMapping("/form/code/preview")
    public Result formCodePreview(@RequestBody FormDataVo formDataVo) {
        return Result.success(generatorService.generateFormCode(formDataVo));
    }

    @HasAuth("code-generator-code-preview:download")
    @PostMapping("/database/table/generate")
    public void datasourceTableGenerate(@RequestBody CodeGenerateVo codeGenerateVo, HttpServletResponse response)
        throws Exception {
        List<GeneratedCode> generatedCodeList = generatorService.getTableGeneratedCode(codeGenerateVo);
        String className = StringUtils.mapUnderscoreToCamelCase(
            StringUtils.removePrefix(codeGenerateVo.getRemoveTableNamePrefix(), codeGenerateVo.getTableName()), 0,
            true);
        String file = toFile(className, generatedCodeList);
        String zipFile = ZipUtils.toZip(className + ".zip", file, true);
        HttpUtils.writeFile(response, null, zipFile, true);
    }

    private String toFile(String className, List<GeneratedCode> generatedCodeList) {
        String dir =
            System.getProperty("java.io.tmpdir") + File.separator + "flame" + File.separator + "code" + File.separator;
        generatedCodeList.forEach(data -> {
            try {
                String location = dir + data.getLocation();
                String fileLocation = location + File.separator + data.getFilename();
                File directory = new File(location);
                if (!directory.exists()) {
                    directory.mkdirs();
                }

                File file = new File(fileLocation);
                if (file.exists()) {
                    file.delete();
                }

                FileOutputStream outputStream = new FileOutputStream(file);
                outputStream.write(data.getCode().getBytes(StandardCharsets.UTF_8));
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        return dir + className;
    }

    @HasAuth("code-generator-code-preview")
    @PostMapping("/database/table/generate/preview")
    public Result datasourceTableGeneratePreview(@RequestBody CodeGenerateVo codeGenerateVo) throws Exception {
        List<GeneratedCode> generatedCodeList = generatorService.getTableGeneratedCode(codeGenerateVo);
        return Result.success(generatedCodeList);
    }

    @HasAuth("code-generator-columns")
    @PostMapping("/datasource/table/column/list")
    public Result datasourceTableColumnList(@RequestBody DbDatasourceTableVo dbDatasourceTableVo) throws Exception {
        List<DbColumn> dbColumnList = generatorService.listDatasourceTableColumn(dbDatasourceTableVo);
        return Result.success(dbColumnList);
    }

    @HasAuth("code-generator-tables")
    @PostMapping("/datasource/table/list")
    public Result datasourceTableList(@RequestBody DbDatasourceVo dbDatasourceVo) throws Exception {
        return Result.success(generatorService.listDatasourceTable(dbDatasourceVo));
    }

    @HasAuth("code-generator")
    @PostMapping("/datasource/page")
    public PageResult datasourcePage(@RequestBody DbDatasourceVo dbDatasourceVo) {
        return PageResult.success(generatorService.pageDbDatasource(dbDatasourceVo));
    }

    @HasAuth("code-generator")
    @PostMapping("/datasource/selectById")
    public Result datasourceSelectById(@RequestBody DbDatasourceVo dbDatasourceVo) {
        DbDatasource datasource = generatorService.selectById(dbDatasourceVo);
        return Result.success(datasource);
    }

    @HasAuth("code-generator:add")
    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/datasource/add")
    public Result datasourceAdd(@RequestBody DbDatasource dbDataSource) {
        generatorService.addDbDatasource(dbDataSource);
        return Result.success();
    }

    @HasAuth("code-generator:edit")
    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/datasource/update")
    public Result datasourceUpdate(@RequestBody DbDatasource dbDataSource) {
        generatorService.updateDbDatasource(dbDataSource);
        return Result.success();
    }

    @HasAuth("code-generator:delete")
    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/datasource/delete")
    public Result datasourceDelete(@RequestBody DbDatasource dbDataSource) {
        generatorService.deleteDbDatasourceById(dbDataSource);
        return Result.success();
    }

    @HasAuth("code-generator:add")
    @PostMapping("/datasource/test")
    public Result datasourceTest(@RequestBody DbDatasource dbDataSource) throws Exception {
        generatorService.testDatasource(dbDataSource);
        return Result.success();
    }
}
